use crate::ffi::CString;
use alloc::vec::Vec;
use core::ffi::c_char;

pub fn cstr_to_str<'a>(cstr: *const c_char) -> &'a str {
    unsafe {
        let mut len = -1;
        for i in 0..1024 * 1024 {
            if *cstr.offset(i) == 0 {
                len = i;
                break;
            }
        }
        if len < 0 {
            return "";
        }
        cstr_with_len_to_str(cstr, len as usize)
    }
}

pub fn cstr_with_len_to_str<'a>(cstr: *const c_char, len: usize) -> &'a str {
    unsafe { alloc::str::from_utf8_unchecked(core::slice::from_raw_parts(cstr as *const u8, len)) }
}

pub fn str_to_cstring(s: &str) -> CString {
    unsafe { CString::from_vec_unchecked(Vec::from(s)) }
}

pub fn copy_cstr(src: *const c_char, dst: &mut [u8]) {
    if src.is_null() {
        dst[0] = 0;
        return;
    }
    unsafe {
        let len = if libc::strlen(src) - 1 > dst.len() {
            dst.len() - 1
        } else {
            libc::strlen(src)
        };
        if len > 0 {
            core::ptr::copy(src as *const u8, dst.as_mut_ptr(), len);
        }
        dst[len] = 0;
    }
}

pub fn copy_str_to_cslice(src: &str, dst: &mut [c_char]) {
    let l = if src.len() > dst.len() - 1 {
        dst.len() - 1
    } else {
        src.len()
    };
    unsafe {
        core::ptr::copy(src.as_ptr() as *const c_char, dst.as_mut_ptr(), l);
    }
    dst[l] = 0;
}

pub fn copy_slice_to_cstr(src: &[u8], dst: *mut c_char, dst_len: usize) {
    if dst.is_null() || dst_len == 0 {
        return;
    }
    let l = if src.len() > dst_len - 1 {
        dst_len - 1
    } else {
        src.len()
    };
    unsafe {
        if l > 0 {
            core::ptr::copy(src.as_ptr() as *const c_char, dst as *mut c_char, l);
        }
        *dst.offset(l as isize) = 0;
    }
}

pub fn copy_from_cslice_to_cslice(c_src: &[u8], c_dst: &mut [u8]) {
    let mut src_len = unsafe { libc::strlen(c_src.as_ptr() as *const c_char) } as usize;
    if src_len > c_src.len() {
        src_len = c_src.len();
    }
    let l = if src_len > c_dst.len() - 1 {
        c_dst.len() - 1
    } else {
        src_len
    };
    if l > 0 {
        (&mut c_dst[..l]).copy_from_slice(&c_src[..l]);
    }
    c_dst[l] = 0;
}

pub fn copy_cstr_for_two_slice(c_src: &[u8], c_dst: &mut [u8]) {
    unsafe {
        libc::strncpy(
            c_dst.as_mut_ptr() as *mut c_char,
            c_src.as_ptr() as *const c_char,
            c_dst.len(),
        )
    };
}

pub fn copy_cstr_for_two_slice_c_char(c_src: &[c_char], c_dst: &mut [c_char]) {
    unsafe { libc::strncpy(c_dst.as_mut_ptr(), c_src.as_ptr(), c_dst.len()) };
}
